package cn.easy.sql.processor;

import cn.easy.sql.annotation.PrimaryKey;
import cn.easy.sql.annotation.Table;
import cn.easy.sql.annotation.TableField;
import cn.easy.sql.constant.DDLType;
import cn.easy.sql.entity.SqlBuilder;
import cn.easy.sql.utils.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class SqlProcessor {
    public <T> String buildBatchUpdateSql(List<T> entityList, SqlBuilder<T> sqlBuilder) throws IllegalAccessException {
        List<Field> fieldList = getFieldList(sqlBuilder);
        // 构造插入sql 前部分 “insert into table (column1,column1...)”
        StringBuilder builder = buildInsertPrefixSql(DDLType.INSERT,sqlBuilder,fieldList);
        builder.append( " values ");
        for (T t : entityList) {
            builder.append("(");
            for (Field field : fieldList) {
                field.setAccessible(true);
                Object fieldValue = field.get(t);
                builder.append(fieldValue);
                builder.append(",");
            }
            builder.deleteCharAt(builder.length()-1);
            builder.append( ")");
            builder.append(",");
        }
        builder.deleteCharAt(builder.length()-1);
        builder.append(";");
        return builder.toString();
    }

    /**
     * 构造sql前缀
     * @param ddlType sql类型枚举
     * @param sqlBuilder sql构造器
     * @param fieldList 列集合
     * @return sql前缀 sqlBuilder
     */
    private  <T> StringBuilder buildInsertPrefixSql(DDLType ddlType,SqlBuilder<T> sqlBuilder, List<Field> fieldList) {
        assert sqlBuilder != null;
        assert sqlBuilder.getTarget()!= null;
        Class<T> target = sqlBuilder.getTarget();
        String tableName = getTableName(target);

        StringBuilder builder = new StringBuilder();
        if(DDLType.INSERT.equals(ddlType)) {
            builder.append( "insert into ");
            builder.append(tableName);
            builder.append(" (");
            for (Field declaredField : fieldList) {
                String fieldName = getFieldName(declaredField);
                builder.append(fieldName);
                builder.append(",");
            }
            builder.deleteCharAt(builder.length() -1);
            builder.append(")");
        } else if (DDLType.UPDATE.equals(ddlType)) {
            builder.append( "update ");
            builder.append(tableName);
        }else if(DDLType.DELETE.equals(ddlType)) {
            builder.append("delete from ");
            builder.append(tableName);
        }
        return builder;
    }

    /**
     * 获取需要生成sql的字段，即列名
     * @param sqlBuilder sql构造器
     * @return 列集合
     */
    private <T> List<Field> getFieldList(SqlBuilder<T> sqlBuilder) {
        Field[] declaredFields = sqlBuilder.getTarget().getDeclaredFields();
        List<Field> fieldList = new ArrayList<>();
        List<Field> primaryKeyList = new ArrayList<>();
        for (Field declaredField : declaredFields) {
            if(declaredField.isAnnotationPresent(TableField.class)) {
                fieldList.add(declaredField);
                continue;
            }
            if((declaredField.isAnnotationPresent(PrimaryKey.class)) && sqlBuilder.getNeedPrimaryKey()) {
                primaryKeyList.add(declaredField);
            }
        }
        primaryKeyList.addAll(fieldList);
        return primaryKeyList;
    }

    /**
     * 获取构造sql的表名
     * @param target 生成sql的目标类
     * @return 表明
     */
    private static <T> String getTableName(Class<T> target) {
        //获取表名，如果不存在注解，或者注解没有值，则将当前类名驼峰转下划线
        Table tableAnnotation = target.getAnnotation(Table.class);
        String tableName = "";
        if(tableAnnotation == null || !StringUtils.hasText(tableAnnotation.value())) {
            tableName = StringUtils.toUnderlineCase(target.getName());
        }else {
            tableName = tableAnnotation.value();
        }
        return tableName;
    }

    /**
     * 获取字段名，如果注解名没有指定名称，使用字段名驼峰转下划线
     * @param declaredField 字段反射值
     * @return 字段名 列名
     */
    private static String getFieldName(Field declaredField) {
        String fieldName = StringUtils.toUnderlineCase(declaredField.getName());
        if((declaredField.isAnnotationPresent(TableField.class)
                && StringUtils.hasText(declaredField.getAnnotation(TableField.class).value())

        )) {
            fieldName =  declaredField.getAnnotation(TableField.class).value();
        } else if((declaredField.isAnnotationPresent(PrimaryKey.class)
                && StringUtils.hasText(declaredField.getAnnotation(PrimaryKey.class).value())
                )){

            fieldName =  declaredField.getAnnotation(PrimaryKey.class).value();
        }
        return fieldName;
    }
}
